﻿#include <iostream>
#include <vector>
#include <map>

using namespace std;

struct Point
{
	int _x;
	int _y;
};
class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)
		:_year(year)
		, _month(month)
		, _day(day)
	{
		cout << "Date(int year,int month,int day)" << endl;
	}
	Date(const Date& d)
		:_year(d._year)
		, _month(d._month)
		, _day(d._day)
	{
		cout << "Date(const Date& d)" << endl;
	}


private:
	int _year;
	int _month;
	int _day;
};


void test1()
{
	// C++98⽀持的
	int a1[] = { 1, 2, 3, 4, 5 };
	int a2[5] = { 0 };
	Point p = { 1, 2 };

	// C++11⽀持的
	// 内置类型⽀持
	int x1 = { 2 };
	// ⾃定义类型⽀持
	// 这⾥本质是⽤{ 2025, 1, 1}构造⼀个Date临时对象
	// 临时对象再去拷贝构造d1，编译器优化后合⼆为⼀变成{ 2025, 1, 1}直接构造初始化d1

	// 运⾏⼀下，我们可以验证上⾯的理论，发现是没调⽤贝构造的
	Date d1 = { 2025, 1, 1 };
	// 这⾥d2引⽤的是{ 2024, 7, 25 }构造的临时对象
	const Date& d2 = { 2024, 7, 25 };

	// 需要注意的是C++98⽀持单参数时类型转换，也可以不⽤{}
	Date d3 = { 2025 };
	Date d4 = 2025;

	cout << endl;

	// 可以省略掉=
	Point p1{ 1, 2 };
	int x2{ 2 };
	Date d6{ 2024, 7, 25 };
	const Date& d7{ 2024, 7, 25 };

	// 不⽀持，只有{}初始化，才能省略=
	// Date d8 2025;

	vector<Date> v;
	v.push_back(d1);
	v.push_back(Date(2025, 1, 1));

	// ⽐起有名对象和匿名对象传参，这⾥{}更有性价⽐
	v.push_back({ 2025, 1, 1 });
}

void test2()
{
	std::initializer_list<int> mylist;
	mylist = { 10, 20, 30 };
	cout << endl << sizeof(mylist) << endl;

	// 这⾥begin和end返回的值initializer_list对象中存的两个指针
	// 这两个指针的值跟i的地址跟接近，说明数组存在栈上
	int i = 0;
	cout << mylist.begin() << endl;
	cout << mylist.end() << endl;
	cout << &i << endl;

	// {}列表中可以有任意多个值
	// 这两个写法语义上还是有差别的，第⼀个v1是直接构造，
	// 第⼆个v2是构造临时对象+临时对象拷贝v2+优化为直接构造
	vector<int> v1({ 1,2,3,4,5 });
	vector<int> v2 = { 1,2,3,4,5 };
	const vector<int>& v3 = { 1,2,3,4,5 };

	// 这⾥是pair对象的{}初始化和map的initializer_list构造结合到⼀起⽤了
	map<string, string> dict = { {"sort", "排序"}, {"string", "字符串"} };

	// initializer_list版本的赋值⽀持
	v1 = { 10,20,30,40,50 };

}
void test3()
{
	// 左值：可以取地址
	// 以下的p、b、c、*p、s、s[0]就是常见的左值
	int* p = new int(0);
	int b = 1;
	const int c = b;
	*p = 10;
	string s("111111");
	s[0] = 'x';
	cout << &c << endl;
	cout << (void*)&s[0] << endl << endl;

	// 右值：不能取地址
	double x = 1.1, y = 2.2;

	// 以下⼏个10、x + y、fmin(x, y)、string("11111")都是常见的右值
	10;
	x + y;
	fmin(x, y);
	string("11111");

	//cout << &10 << endl;
	//cout << &(x+y) << endl;
	//cout << &(fmin(x, y)) << endl;
	//cout << &string("11111") << endl;
}
int main()
{
	test1();
	test2();
	test3();

	// 左值：可以取地址
	// 以下的p、b、c、*p、s、s[0]就是常见的左值
	int* p = new int(0);
	int b = 1;
	const int c = b;
	*p = 10;
	string s("111111");
	s[0] = 'x';
	double x = 1.1, y = 2.2;

	// 左值引用给左值取别名
	int& r1 = b;
	int*& r2 = p;
	int& r3 = *p;
	string& r4 = s;
	char& r5 = s[0];

	// 右值引⽤给右值取别名
	int&& rr1 = 10;
	double&& rr2 = x + y;
	double&& rr3 = fmin(x, y);
	string&& rr4 = string("11111");

	// 左值引用不能直接引用右值，但是const左值引用可以引用右值
	const int& rx1 = 10;
	const double& rx2 = x + y;
	const double& rx3 = fmin(x, y);
	const string& rx4 = string("11111");

	// 右值引用不能直接引用左值，但是右值引⽤可以引用move(左值)
	int&& rrx1 = move(b);
	int*&& rrx2 = move(p);
	int&& rrx3 = move(*p);
	string&& rrx4 = move(s);
	string&& rrx5 = (string&&)s;

	// b、r1、rr1都是变量表达式，都是左值
	cout << &b << endl;
	cout << &r1 << endl;
	cout << &rr1 << endl;

	// 这⾥要注意的是，rr1的属性是左值，所以不能再被右值引用绑定，除非move⼀下
	int& r6 = r1;
	// int&& rrx6 = rr1;
	int&& rrx6 = move(rr1);

	return 0;
}
